/*
 * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
 *
 */

#include "ukuitaskwidget.h"
#include "ukuitaskgroup.h"
#include "ukuitaskbar.h"

//#include <UKUi/Settings>
#include "../panel/common/ukuisettings.h"

#include <QDebug>
#include <QTimer>
#include <QMenu>
#include <QAction>
#include <QContextMenuEvent>
#include <QPainter>
#include <QPainterPath>
#include <QDrag>
#include <QMouseEvent>
#include <QMimeData>
#include <QApplication>
#include <QDragEnterEvent>
#include <QStylePainter>
#include <QStyleOptionToolButton>
#include <QDesktopWidget>
#include <QScreen>

#include "ukuitaskgroup.h"
#include "ukuitaskbar.h"
#include "ukuitaskclosebutton.h"
#include "common/common.h"

#include <KWindowSystem/KWindowSystem>
// Necessary for closeApplication()
#include <KWindowSystem/NETWM>
#include <QtX11Extras/QX11Info>

#define WAYLAND_GROUP_HIDE     0
#define WAYLAND_GROUP_ACTIVATE 1
#define WAYLAND_GROUP_CLOSE    2

UKUITaskWidget::UKUITaskWidget(const WindowId& window, UKUITaskBar * taskbar, QWidget *parent) :
    QWidget(parent),
    m_sdkWindow(window),
    m_parentTaskBar(taskbar),
    m_plugin(m_parentTaskBar->plugin()),
    m_DNDTimer(new QTimer(this)),
    m_timer(new QTimer(this))
{
    Q_INIT_RESOURCE(qml);
    Q_ASSERT(taskbar);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setMinimumWidth(1);
    setMinimumHeight(1);
    setAcceptDrops(true);
    m_status=NORMAL;
    setAttribute(Qt::WA_TranslucentBackground);//设置窗口背景透明
    setWindowFlags(Qt::FramelessWindowHint);   //设置无边框窗口

    //for layout
    m_closeBtn =  new UKUITaskCloseButton(m_sdkWindow, this);
    m_closeBtn->setIconSize(QSize(19,19));
    m_closeBtn->setFixedSize(QSize(19,19));
    m_closeBtn->hide();
    m_titleLabel = new QLabel(this);
    m_titleLabel->setMargin(0);

    m_thumbnailLabel = new QLabel(this);
    m_thumbnailLabel->setVisible(false);
    m_appIcon = new QLabel(this);
    m_vWindowsLayout = new QVBoxLayout(this);
    m_topBarLayout = new QHBoxLayout(this);
    m_topBarLayout->setContentsMargins(0,0,0,0);

    m_titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    m_appIcon->setAlignment(Qt::AlignLeft);
    m_appIcon->setScaledContents(false);


    // 自动缩放图片
    m_thumbnailLabel->setScaledContents(true);

    // 设置控件缩放方式
    QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    m_titleLabel->setSizePolicy(sizePolicy);

    // 设置控件最大尺寸
    m_titleLabel->setFixedHeight(32);
    m_titleLabel->setMinimumWidth(1);
    m_thumbnailLabel->setMinimumSize(QSize(1, 1));

    m_titleLabel->setContentsMargins(0, 0, 5, 0);
    //    m_topBarLayout->setSpacing(5);
    m_topBarLayout->addWidget(m_appIcon, 0, Qt::AlignLeft | Qt::AlignVCenter);
    m_topBarLayout->addWidget(m_titleLabel, 10, Qt::AlignLeft);
    m_topBarLayout->addWidget(m_closeBtn, 0, Qt::AlignRight);
    m_vWindowsLayout->addLayout(m_topBarLayout);
    m_vWindowsLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
    this->setLayout(m_vWindowsLayout);
    updateSdkText();
    updateSdkIcon();
    m_DNDTimer->setSingleShot(true);
    m_DNDTimer->setInterval(700);
    connect(m_DNDTimer, SIGNAL(timeout()), this, SLOT(activateSdkWithDraggable()));
    connect(m_closeBtn, SIGNAL(sigClicked()), this, SLOT(closeSdkApplication()));
    //qml动态预览
    getSysTransparency();
    m_tempView = new QQuickView();
    m_tempView->setSource(QUrl("qrc:/qml/preview.qml"));
    m_tempView->setResizeMode(QQuickView::SizeRootObjectToView);
    QSurfaceFormat surfaceFormat;
    surfaceFormat.setAlphaBufferSize(8);//设置透明通道位数
    m_tempView->setFormat(surfaceFormat);
    m_tempView->setClearBeforeRendering(true);
    if (m_tempView->rendererInterface()->graphicsApi() < 2) {
        m_canUseOpenGL = false;
    }

    m_thumbnailPreview = new QWidget(this);
    m_thumbnailPreview = QWidget::createWindowContainer(m_tempView, this);
    m_thumbnailPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    m_tempItem = m_tempView->rootObject();
    // emit in qml
    QObject::connect(m_tempItem, SIGNAL(sendWinId()), this, SLOT(raiseSdkApplication()));
    QObject::connect(m_tempItem, SIGNAL(sendMoveEntered()), this, SLOT(keepShow()));
    QObject::connect(m_tempItem, SIGNAL(sendMoveLeaved()), this, SLOT(keepLeave()));
    QObject::connect(m_tempItem, SIGNAL(sendRightButtonClicked()), this, SLOT(rightButtonMenu()));

    m_timer->setTimerType(Qt::PreciseTimer);
    connect(m_timer, SIGNAL(timeout()), SLOT(sendSigToKwin()));
}

UKUITaskWidget::~UKUITaskWidget()
{
    this->deleteLater();
}

void UKUITaskWidget::updateSdkText()
{
    QString title = WindowManager::getWindowTitle(m_sdkWindow);

    m_titleLabel->setToolTip(title);
    QTimer::singleShot(0,this,[=](){
        QString formatAppName = m_titleLabel->fontMetrics().elidedText(title,Qt::ElideRight, m_titleLabel->width());
        m_titleLabel->setText(formatAppName);
    });
}

void UKUITaskWidget::updateSdkIcon()
{
    QIcon ico;
    if (ico.isNull()) {
        ico = WindowManager::getWindowIcon(m_sdkWindow);
        if (ico.isNull()) {
            ico = QIcon::fromTheme(getAndroidAppIcon(m_sdkWindow));
        }
    }

    m_appIcon->setPixmap(ico.pixmap(QSize(19,19)));
    setIcon(ico);
}

QString UKUITaskWidget::getAndroidAppIcon(const WindowId& windowId)
{
    QString iconName;
    QString appName;
    quint32 winPid = WindowManager::getPid(windowId);
    QString cmd = "ps -p " + QString::number(winPid) + " -f | grep " + QString::number(winPid);
    QStringList options;
    options << "-c" << cmd;
    m_cmdProcess = new QProcess(this);
    m_cmdProcess->start("/bin/bash", options);
    m_cmdProcess->waitForStarted();
    m_cmdProcess->waitForFinished();
    QString cmdRet = QString (m_cmdProcess->readAllStandardOutput());
    QStringList strlist = cmdRet.split(" ", QString::SkipEmptyParts);
    for (int i = 0; i < strlist.size(); i++) {
        if (strlist.at(i) == "-p") {
            appName = strlist.at(i+1);
            break;
        }
    }
    iconName = QDir::homePath() + "/.local/share/icons/" + appName + ".svg";
    if (!QFile(iconName).exists()) {
        iconName = QDir::homePath() + "/.local/share/icons/" + appName + ".png";
        if (!QFile(iconName).exists()) {
            iconName = "application-x-desktop";
        }
    }
    return iconName;
}


void UKUITaskWidget::setPixmap(QPixmap _pixmap)
{
    m_pixmap = _pixmap;
}

void UKUITaskWidget::setIcon(QIcon icon)
{
    m_icon = icon;
}

void UKUITaskWidget::mousePressEvent(QMouseEvent* event)
{
    const Qt::MouseButton b = event->button();

    if (Qt::LeftButton == b) {
        activateSdkWithDraggable();
    }

    QWidget::mousePressEvent(event);
}

void UKUITaskWidget::mouseReleaseEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        //        if (isChecked())
        //            minimizeApplication();
        //        else
        raiseSdkApplication();
    }
    m_status = NORMAL;
    m_closeBtn->hide();
    update();
    QWidget::mouseReleaseEvent(event);

}

void UKUITaskWidget::enterEvent(QEvent *)
{
    m_status = HOVER;
    m_closeBtn->show();
    sendSigToKwin();
    repaint();
}

void UKUITaskWidget::leaveEvent(QEvent *)
{
    m_status = NORMAL;
    m_closeBtn->hide();
    repaint();
}
QMimeData * UKUITaskWidget::mimeData()
{
    QMimeData *mimedata = new QMimeData;
    QByteArray ba;
    QDataStream stream(&ba,QIODevice::WriteOnly);
    stream << (qlonglong)(m_window);
    mimedata->setData(mimeDataFormat(), ba);
    return mimedata;
}

void UKUITaskWidget::mouseMoveEvent(QMouseEvent* event)
{
}

void UKUITaskWidget::keepShow()
{
    m_status = HOVER;
    m_closeBtn->show();
    repaint();
    //TODO:发信号给group
    emit signalKeepShow(true);

    m_timer->start(200);
}

void UKUITaskWidget::sendSigToKwin()
{
    QDBusMessage message = QDBusMessage::createSignal("/", "com.ukui.kwin", "panelUpdateLayer");
    QList<QVariant> args;
    quint32 m_wid = m_sdkWindow.toInt();
    args.append(m_wid);
    message.setArguments(args);
    QDBusConnection::sessionBus().send(message);

}

void UKUITaskWidget::sendCloseSigToKWin()
{
    QDBusMessage message = QDBusMessage::createSignal("/", "com.ukui.kwin", "panelNotUpdateLayer");
    QList<QVariant> args;
    bool flag = true;
    args.append(flag);
    message.setArguments(args);
    QDBusConnection::sessionBus().send(message);
}

void UKUITaskWidget::keepLeave()
{
    if (m_timer->isActive()) {
        m_timer->stop();
    }
    m_status = NORMAL;
    m_closeBtn->hide();
    repaint();
    emit signalKeepLeave(true);

    if(this->isVisible()) {
        return;
    }
}

void UKUITaskWidget::contextMenuEvent(QContextMenuEvent *event)
{
    if (!m_plugin) {
        return;
    }
    rightButtonMenu();
}

void UKUITaskWidget::rightButtonMenu()
{
    WindowInfo info = WindowManager::getwindowInfo(m_sdkWindow);
    QMenu * menu = new QMenu(tr("Widget"));
    menu->setAttribute(Qt::WA_DeleteOnClose);
    /* 对应预览图右键功能 关闭 还原 最大化  最小化 置顶 取消置顶*/
    QAction *close = menu->addAction(QIcon::fromTheme("window-close-symbolic"), tr("close"));
    QAction *restore = menu->addAction(QIcon::fromTheme("window-restore-symbolic"), tr("restore"));

    QAction *maxim = menu->addAction(QIcon::fromTheme("window-maximize-symbolic"), tr("maximaze"));
    maxim->setEnabled(!info.isMaximized());

    QAction *minim = menu->addAction(QIcon::fromTheme("window-minimize-symbolic"), tr("minimize"));
    QAction *above = menu->addAction(QIcon::fromTheme("ukui-fixed-symbolic"), tr("above"));
    QAction *clear = menu->addAction(QIcon::fromTheme("ukui-unfixed-symbolic"), tr("clear"));

    connect(close, SIGNAL(triggered()), this, SLOT(closeSdkApplication()));
    connect(restore, SIGNAL(triggered()), this, SLOT(deMaximizeApplication()));
    connect(maxim, SIGNAL(triggered()), this, SLOT(maximizeApplication()));
    connect(minim, SIGNAL(triggered()), this, SLOT(minimizeApplication()));
    connect(above, SIGNAL(triggered()), this, SLOT(setWindowKeepAbove()));
    connect(clear, SIGNAL(triggered()), this, SLOT(setWindowStatusClear()));
    connect(menu, &QMenu::aboutToHide, [this] {emit closeSigtoPop();});
    above->setEnabled(!info.isKeepAbove());
    clear->setEnabled(info.isKeepAbove());
    menu->exec(cursor().pos());
    plugin()->willShowWindow(menu);
    menu->show();
}

bool UKUITaskWidget::isApplicationActive() const
{
    return KWindowSystem::activeWindow() == m_window;
}

void UKUITaskWidget::activateSdkWithDraggable()
{
    // raise app in any time when there is a drag
    // in progress to allow drop it into an app
    raiseSdkApplication();
    WindowManager::activateWindow(m_sdkWindow);
}

void UKUITaskWidget::raiseSdkApplication()
{
    KWindowSystem::clearState(m_sdkWindow.toInt(), NET::Hidden);

    WindowInfo info = WindowManager::getwindowInfo(m_sdkWindow);
    if (info.isMinimized()) {
        WindowManager::activateWindow(m_sdkWindow);
    } 
    WindowManager::activateWindow(m_sdkWindow);
    sendCloseSigToKWin();
    emit windowActived();
}

/************************************************

 ************************************************/
void UKUITaskWidget::minimizeApplication()
{
    WindowManager::minimizeWindow(m_sdkWindow);
}

/************************************************

 ************************************************/
void UKUITaskWidget::maximizeApplication()
{
    WindowManager::maximizeWindow(m_sdkWindow);
    if (!isApplicationActive()) {
        raiseSdkApplication();
    }
}

void UKUITaskWidget::deMaximizeApplication()
{
    KWindowSystem::clearState(m_window, NET::Max);

    if (!isApplicationActive()) {
        raiseSdkApplication();
    }
}


void UKUITaskWidget::setWindowKeepAbove()
{
    if (!isApplicationActive()) {
        raiseSdkApplication();
    }
    WindowManager::keepWindowAbove(m_sdkWindow);
}

void UKUITaskWidget::setWindowStatusClear()
{
    WindowManager::keepWindowAbove(m_sdkWindow);
}

void UKUITaskWidget::closeSdkApplication()
{
    // FIXME: Why there is no such thing in KWindowSystem??
    WindowManager::closeWindow(m_sdkWindow);
    sendCloseSigToKWin();
}

void UKUITaskWidget::getSysTransparency()
{
    const QByteArray transparency_id(TRANSPARENCY_SETTINGS);
    if(QGSettings::isSchemaInstalled(transparency_id)) {
        m_transparencyGsettings = new QGSettings(transparency_id);
        m_transparency = m_transparencyGsettings->get(TRANSPARENCY_KEY).toDouble();
        this->update();
        connect(m_transparencyGsettings, &QGSettings::changed, this, [=] (const QString &key){
            if(key == TRANSPARENCY_KEY) {
                m_transparency = m_transparencyGsettings->get(TRANSPARENCY_KEY).toDouble();
                this->update();
            }
        });
    } else {
        m_transparency=0.75;
    }

}

void UKUITaskWidget::paintEvent(QPaintEvent *event)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    QColor color= palette().color(QPalette::BrightText);
    color.setAlphaF(0.15);
    p.setPen(color);
    p.drawRoundedRect(opt.rect,12,12);

    QPainterPath rectPath;
    rectPath.addRoundedRect(this->rect().adjusted(1, 1, -1, -1), 12, 12);
    QPixmap pixmap(this->rect().size());
    pixmap.fill(Qt::transparent);

    QPainter pixmapPainter(&pixmap);
    pixmapPainter.setRenderHint(QPainter::Antialiasing);

    pixmapPainter.drawPath(rectPath);
    pixmapPainter.end();

    // 模糊这个黑底
    extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed);
    QImage img = pixmap.toImage();
    qt_blurImage(img, 10, false, false);

    // 挖掉中心
    pixmap = QPixmap::fromImage(img);
    QPainter pixmapPainter2(&pixmap);
    pixmapPainter2.setRenderHint(QPainter::Antialiasing);
    pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear);
    pixmapPainter2.drawPath(rectPath);

    // 绘制阴影
//    p.drawPixmap(this->rect(), pixmap, pixmap.rect());

    // 绘制底色
    p.save();
    QColor col;
    switch (m_status)
    {
    case NORMAL:
        col = this->palette().color(QPalette::Window);
        break;

    case HOVER:
        col = this->palette().color(QPalette::Button);
        break;

    case PRESS:
        col = this->palette().color(QPalette::Button);
        break;
    }

    col.setAlphaF(m_transparency);
    p.fillPath(rectPath, col);
    //预览窗标题文字颜色
    QPalette pal = m_titleLabel->palette();
    QColor coll = pal.color( QPalette::Text);
    pal.setColor(QPalette::Text, coll);
    m_titleLabel->setPalette(pal);
    p.restore();

}

bool UKUITaskWidget::hasDragAndDropHover() const
{
    return m_DNDTimer->isActive();
}
void UKUITaskWidget::updateTitle()
{
    updateSdkText();
}

void UKUITaskWidget::setThumbNail(QPixmap _pixmap)
{
    m_thumbnailLabel->setVisible(true);
    m_thumbnailLabel->setPixmap(_pixmap);
    m_vWindowsLayout->addWidget(m_thumbnailLabel, Qt::AlignCenter, Qt::AlignCenter);
}

void UKUITaskWidget::removeThumbNail()
{
    if (m_thumbnailLabel) {
        m_vWindowsLayout->removeWidget(m_thumbnailLabel);
        m_thumbnailLabel->setParent(NULL);
        m_thumbnailLabel->deleteLater();
        m_thumbnailLabel = NULL;
    }
}

void UKUITaskWidget::addThumbNail()
{
    if (!m_thumbnailLabel) {
        m_thumbnailLabel = new QLabel(this);
        m_thumbnailLabel->setScaledContents(true);
        m_thumbnailLabel->setMinimumSize(QSize(1, 1));
        //        m_vWindowsLayout->addLayout(m_topBarLayout, 100);
        //m_vWindowsLayout->addWidget(m_thumbnailLabel, 0, Qt::AlignCenter);
    } else {
        return;
    }
}

void UKUITaskWidget::setLiveThumbNail(int w, int h)
{
    QColor col;
    col = this->palette().color(QPalette::Window);
    col.setAlphaF(m_transparency);
    m_tempView->setColor(col);

    m_tempRecl = m_tempItem->findChild<QObject *>("tmpWindowThumbnail");
    m_tempRecl->setProperty("winId", m_sdkWindow.toInt());
    m_thumbnailPreview->setFixedSize(w,h);
    m_vWindowsLayout->addWidget(m_thumbnailPreview);

    float tmp_imgWidth = w;
    float tmp_imgHeight = h;
    QObject *pRect = m_tempView->findChild<QObject *>("rect1");
    QMetaObject::invokeMethod(pRect, "setValue", Q_ARG(QVariant, QVariant(tmp_imgWidth)), Q_ARG(QVariant, QVariant(tmp_imgHeight)));

}

void UKUITaskWidget::removeLiveThumbNail()
{
    if (m_thumbnailPreview) {
        m_vWindowsLayout->removeWidget(m_thumbnailPreview);
    }
}

void UKUITaskWidget::setTitleFixedWidth(int size)
{
    m_titleLabel->setFixedWidth(size);
    m_titleLabel->adjustSize();
}

void UKUITaskWidget::setThumbMaximumSize(int w) {
    this->m_thumbnailLabel->setMaximumWidth(w);
}

void UKUITaskWidget::setThumbScale(bool val) {
    this->m_thumbnailLabel->setScaledContents(val);
}
